/**
 * 
 */
package org.gbif.metadata.webapp.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletContext;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

import org.apache.commons.io.FileUtils;
import org.apache.struts2.util.ServletContextAware;
import org.appfuse.webapp.action.BaseAction;
import org.gbif.metadata.eml.Eml;
import org.jibx.runtime.BindingDirectory;
import org.jibx.runtime.IBindingFactory;
import org.jibx.runtime.IUnmarshallingContext;

/**
 * Actions for browsing old documents within the /metadata directory
 * 
 * @author davemartin
 */
public class BrowseMetadataAction extends BaseAction implements ServletContextAware {

	private static final long serialVersionUID = 8242489438603579576L;

	protected String metadataDirectoryPath = "/metadata";
	
	protected String selectedFile = null;
	
	protected List<Document> documents = null;
	
	protected ServletContext context;
	
	/**
	 * View documents.
	 * 
	 * @return
	 */
	public String viewDocuments(){
	
		String directoryFilePath = this.context.getRealPath("/");
		log.debug("Looking in directory :" + directoryFilePath);
		File metadataDirectory = new File(directoryFilePath+metadataDirectoryPath);
		
		if(!metadataDirectory.exists()){
			//create it
			try {
				FileUtils.forceMkdir(metadataDirectory);
			} catch (IOException e) {
				log.error(e.getMessage(), e);
				return ERROR;
			}
		}		
		
		File[] files = metadataDirectory.listFiles();
		this.documents = new ArrayList<Document>();
		for(File file: files){
			log.debug("reading file:"+file.getName());
			//SAX parse pulling out the document title
			Document doc = getDocument(file);
			if(doc!=null){
				log.debug("adding doc :"+doc.getTitle());
				documents.add(doc);	
			}
		}
		return SUCCESS;
	}

	/**
	 * View documents.
	 * 
	 * @return
	 */
	public String editDocument(){
		File fileToEdit = new File(selectedFile);
		try {
			IBindingFactory bfact = BindingDirectory.getFactory(Eml.class);
			IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
			Eml eml = (Eml) uctx.unmarshalDocument(new FileInputStream(fileToEdit), null);
			getRequest().getSession().setAttribute("currentDoc", fileToEdit);
			getRequest().getSession().setAttribute("eml", eml);
		}catch(Exception e){
			log.error(e.getMessage(), e);
			return ERROR;
		}
     return SUCCESS;
	}
	
	/**
	 * View documents.
	 * 
	 * @return
	 */
	public String deleteDocument(){
		File fileToDelete = new File(selectedFile);
		if(fileToDelete.exists()){
			fileToDelete.delete();
			//is this file currently in the session??
			File currentDoc = (File) getSession().getAttribute("currentDoc");
			if(currentDoc!=null && currentDoc.equals(fileToDelete)){
				log.debug("Removing doc that is currently in the session");
				getSession().removeAttribute("currentDoc");
				getSession().removeAttribute("eml");
			}
		}
		return SUCCESS;
	}	
	
	/**
	 * STAX parse the document pulling out the title and abstract.
	 * Returns null if these elements are inaccessible or the file
	 * was not parseable.
	 * 
	 * @param file
	 * @return
	 */
	private Document getDocument(File file) {
		try {
			FileInputStream input = new FileInputStream(file);
	    	XMLInputFactory factory = XMLInputFactory.newInstance();
	    	XMLStreamReader parser = factory.createXMLStreamReader(input);
	    	
	    	boolean inTitle = false;
	    	boolean inAbstract = false;
	    	boolean inAbstractPara = false;
	    	String title = null;
	    	String _abstract = null;
	    	
	    	boolean finished = false;
	    	
	    	while (!finished) {
	    	    int event = parser.next();
	    	    if (event == XMLStreamConstants.END_DOCUMENT) {
	    	       parser.close();
	    	       finished = true;
	    	       break;
	    	    }
	    	    if (event == XMLStreamConstants.START_ELEMENT) {
	    	        if("title".equals(parser.getLocalName())){
	    	        	inTitle = true;
	    	        } else if("abstract".equals(parser.getLocalName())
	    	        		|| (inAbstract && "para".equals(parser.getLocalName()))
	    	        	){
	    	        	inAbstract = true;
	    	        	if("para".equals(parser.getLocalName())){
	    	        		inAbstractPara = true;
	    	        	}
	    	        	
	    	        } else {
	    	        	inTitle=inAbstract=inAbstractPara=false;
	    	        }
	    	    }        	    
	    	    if (event == XMLStreamConstants.CHARACTERS) {
	    	    	if(inAbstractPara)
	    	    		_abstract = parser.getText();
	    	    	if(inTitle)
	    	    		title = parser.getText();
	    	    }
	    	    if(title!=null && _abstract!=null)
	    	    	finished=true;
	    	}
	    	
	    	Document doc = new Document();
	    	doc.setFile(file);
	    	doc.setTitle(title);
	    	doc.setDescription(_abstract);
	    	doc.setFilePath(file.getPath());
	    	doc.setLastModified(new Date(file.lastModified()));
	    	return doc;
		} catch(Exception e){
			log.error("There was a problem parsing the file :"+file.getPath());
			log.error(e.getMessage(), e);
		}
		return null;
	}


	public void setServletContext(ServletContext context) {
		this.context = context;
	}

	public String getMetadataDirectoryPath() {
		return metadataDirectoryPath;
	}

	public void setMetadataDirectoryPath(String metadataDirectoryPath) {
		this.metadataDirectoryPath = metadataDirectoryPath;
	}

	public String getSelectedFile() {
		return selectedFile;
	}

	public void setSelectedFile(String selectedFile) {
		this.selectedFile = selectedFile;
	}
	
	public List<Document> getDocuments() {
		return documents;
	}

	public void setDocuments(List<Document> documents) {
		this.documents = documents;
	}	
}